package com.lzyyj.gmis.base.service;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.lzyyj.common.BeanUtilsExt;
import com.lzyyj.common.BeanWrapper;
import com.lzyyj.common.GenericsUtils;
import com.lzyyj.common.Page;
import com.lzyyj.gmis.base.dao.IBaseDao;

public class BaseMapService<T, PK extends Serializable,T2> implements IBaseService<T, PK>,Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1627171223163709523L;
	
	private static final Log log = LogFactory.getLog(BaseMapService.class);

	private ISystemService systemService;
	
	@Override
	public ISystemService getSystemService() {
		return systemService;
	}

	@Override
	public void setSystemService(ISystemService systemService) {
		this.systemService = systemService;
	}
	
	@Override
	public <T1, PK1 extends Serializable> IBaseService<T1, PK1> getBaseService(Class<T1> clazz1) {
		IBaseService<T1, PK1> baseService = null;
		
		if (serviceMap.containsKey(clazz1)){
			baseService = (IBaseService<T1, PK1>)serviceMap.get(clazz1);
		}
		
		return baseService;
	}

	/**
	 * 接驳旧的业务服务代码
	 */
	private Object oldService;

	public Object getOldService() {
		return oldService;
	}

	public void setOldService(Object oldService) {
		this.oldService = oldService;
	}

	private IBaseDao<T2, PK> baseDao;

	public IBaseDao<T2, PK> getBaseDao() {
		return baseDao;
	}

	public void setBaseDao(IBaseDao<T2, PK> baseDao) {
		this.baseDao = baseDao;
	}

	public IBaseDao<T2, PK> useBaseDao() throws Exception {
		if (baseDao==null){
			throw new Exception("部署错误：没有配置 数据库访问 Dao");
		}
		return baseDao;
	}

	/**
	 * 本服务管理对象模型，可能是接口
	 */
	private Class<T> entityClass;
	
	/**
	 * 获取管理的实体类
	 */
	@Override
	public Class<T> getEntityClass() {
		return entityClass;
	}
	
	/**
	 * 本服务管理的对象模型的默认实现类
	 */
	private Class<T2> defaultClass;

	public Class<T2> getDefaultClass() {
		return defaultClass;
	}

	public void setDefaultClass(Class<T2> defaultClass) {
		this.defaultClass = defaultClass;
	}
	
	private String pkName;
	
	public String getPkName() {
		return pkName;
	}

	public void setPkName(String pkName) {
		this.pkName = pkName;
	}

	private Class<T2> sourceClass;

	public Class<T2> getSourceClass() {
		return sourceClass;
	}

	public void setSourceClass(Class<T2> sourceClass) {
		this.sourceClass = sourceClass;
	}
	
	private String propertyRelation;
	
	public String getPropertyRelation() {
		return propertyRelation;
	}

	public void setPropertyRelation(String propertyRelation) {
		this.propertyRelation = propertyRelation;
	}

	private BeanWrapper entityWrapper;

	public BeanWrapper getWrapper() {
		if (entityWrapper==null){
			Class<?> clazz = getBaseDao().getEntityClass();
			entityWrapper = BeanWrapper.getInstance(entityClass, propertyRelation, clazz);
		}
		return entityWrapper;
	}

	private static Map<Class<?>, IBaseService<?, Serializable>> serviceMap = new HashMap<Class<?>, IBaseService<?,Serializable>>();
	
	private static int createCount = 0;
		
	protected String moduleId = ""+serialVersionUID;
	
	public String getModuleId() {
		return moduleId;
	}

	public void setModuleId(String moduleId) {
		this.moduleId = moduleId;
	}

	protected String moduleName;
	
	public String getModuleName() {
		if (moduleName==null){
			moduleName="基本功能模块"+moduleId;
		}
		return moduleName;
	}

	public void setModuleName(String moduleName) {
		this.moduleName = moduleName;
	}
	
	/**
	 * 本服务要用到的Dao列表
	 */
	private Map<String, IBaseDao<?, ?>> daoMap = new HashMap<String, IBaseDao<?, ?>>();

	public Map<String, IBaseDao<?, ?>> getDaoMap() {
		return daoMap;
	}

	public void setDaoMap(Map<String, IBaseDao<?, ?>> daoMap) {
		this.daoMap = daoMap;
	}

	protected <E, PK1 extends Serializable> IBaseDao<E, PK1> getDao(Class<IBaseDao<E, PK1>> clazz) {
		IBaseDao<E, PK1> retDao = null;
		
		if (clazz!=null&&daoMap.containsKey(clazz.getSimpleName())){
			retDao = (IBaseDao<E, PK1>)daoMap.get(clazz.getSimpleName());
		}
		
		return retDao;
	}
	
	protected static String[] properties = null;
	
	public String[] getProperties() throws Exception {
		if (properties==null){
			if (getBaseDao()!=null){
				properties = useBaseDao().getProperties();
			}else{
				
			}
		}
		return properties;
	}

	public static void setProperties(String[] properties) {
		BaseMapService.properties = properties;
	}

	protected static Map<String, Object> propertyMap = null;

	public Map<String, Object> getPropertyMap() throws Exception {
		if (propertyMap==null){
			propertyMap = new HashMap<String, Object>();
			for (String property:getProperties()){
				propertyMap.put(property, property);
			}
		}
		return propertyMap;
	}

	public void setPropertyMap(Map<String, Object> value) {
		propertyMap = value;
	}
	
	protected Map<String, Class<?>> foreignKeyMap = new HashMap<String, Class<?>>();
	
	protected Map<String, String> oneToMultFkMap = new HashMap<String, String>();

	@SuppressWarnings("unchecked")
	private void parseEntityClass(Class<T> entityClass) {
		String description;
		if (entityClass==null){
			this.entityClass = (Class<T>)GenericsUtils.getSuperClassGenricType(getClass(), BaseService.class, "T");
			description = "默认构造";
		}else{
			this.entityClass = entityClass;
			description = "带参构造";
		}
		Class<PK> pkClass = (Class<PK>)GenericsUtils.getSuperClassGenricType(getClass(), BaseService.class, 1);
		log.debug(getClass().getSimpleName()+" "+description+"("+(++createCount)+")，"+" 管理实体: "+this.entityClass+" 主键："+pkClass+" ， moduleId："+moduleId+" moduleName:"+ moduleName +"");
	}
	
	public BaseMapService() {
		parseEntityClass(null);
	}

	public BaseMapService(Class<T> clazz) {
		parseEntityClass(clazz);
	}
	
	public BaseMapService(String moduleId, String moduleName) {
		this.moduleId = moduleId;
		this.moduleName = moduleName;
		parseEntityClass(null);
	}

	@Override
	public T getNew() throws Exception{
		T entity = null;
		
		if (entityClass!=null){
			if (entityClass.isInterface()){
				// 管理的实体类是个接口，需要默认实体类
				if (defaultClass!=null){
					T2 entity2 = defaultClass.newInstance();
					entity = getWrapper().wrap(entityClass, entity2);
				}else{
					throw new Exception("管理的接口类未指定默认实现类！");
				}
			}else{
				entity = entityClass.newInstance();
			}
			
		}
		
		return entity;
	}

	@Override
	public T getNew(T example, String propertyList) throws Exception {
		T entity = getNew();
		copyProperties(example, entity, getPropertyList(), false);
		return entity;
	}

	/**
	 * 属性复制
	 * @param source
	 * @param target
	 * @param propertyList
	 * @param persistent 针对外键引用，是否需要进行持久化转换
	 * @throws Exception 
	 */
	public void copyProperties(T source, T target, String propertyList,boolean persistent) throws Exception {

		if (propertyList == null || propertyList.length() == 0) {
			propertyList = getPropertyList();
		}
		String[] fields = propertyList.split(",");
		for (String field : fields) {
			if (field!=null&&field.length()>1){
				try {
					Object value = PropertyUtils.getProperty(source, field);
					if (value==null){
						PropertyUtils.setProperty(target, field, null);
					}else{
						if (value instanceof Integer){
							PropertyUtils.setProperty(target, field, value);
						}else if (value instanceof String){
							PropertyUtils.setProperty(target, field, value);
						}else{
							if (persistent){
								// 改值类型是否是可持久化类型
								if (useBaseDao().isEntity(value.getClass())){
									value = useBaseDao().getByClass(value);
									if (value == null){
										PropertyUtils.setProperty(target, field, null);
									}else{
										PropertyUtils.setProperty(target, field, value);
									}
								}else{
									PropertyUtils.setProperty(target, field, value);
								}
							}else{
								PropertyUtils.setProperty(target, field, value);
							}
						}
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 获得实体类属性列表
	 * @return
	 * @throws Exception 
	 */
	@Override
	public String getPropertyList() throws Exception {
		return useBaseDao().getPropertyList();
	}

	@Override
	public T get(PK id) throws Exception {
		T entityPo = null;
		
		T2 entity = useBaseDao().getById(id);
		if (entity!=null){
			entityPo = getWrapper().wrap(entityClass, entity);
		}
		
		return entityPo;
	}

	@Override
	public T get(T instance) throws Exception {
		return get(instance, null);
	}

	@Override
	public T get(T entity, String propertyList) throws Exception{
		T entityPo = null;
		
		// 是否找到有效处理方法
		boolean processed = false;
		// 属性列表是否得到处理
		boolean propertyProcessed = false;
		if (oldService!=null){
			Method method = BeanUtilsExt.getMethod(oldService.getClass(), "get", entity.getClass(), String.class);
			if (method != null) {
				entity = (T) method.invoke(oldService, new Object[] {entity, propertyList });
				processed = true;
				propertyProcessed = true;
			}
			if (!processed){
				method = BeanUtilsExt.getMethod(oldService.getClass(), "get", entity.getClass());
				if (method != null) {
					entity = (T) method.invoke(oldService, new Object[] {entity});
					processed = true;
				}
			}
		}
		
		if(!processed&&baseDao!=null){
			T2 entity2 = baseDao.getById((PK) BeanUtilsExt.getProperty(entity, pkName));
			if (entity2!=null){
				entityPo = getWrapper().wrap(entityClass, entity2);
			}
		}
		
		if (!processed){
			throw new Exception("未找到有效的处理方法！");
		}
		
		if (!propertyProcessed&&propertyList!=null){
			for(String property:propertyList.split(",")){
				if (property!=null&&property.length()>0){
					throw new Exception("该方法还未完全实现");
				}
			}
		}
		
		return entityPo;
	}

	@Override
	public T getForModify(PK id) throws Exception {
		T entityPo = get(id);
		return entityPo;
	}

	@Override
	public void del(PK id) throws Exception {
		T entityPo = get(id);
		if (entityPo == null) {
			throw new Exception("参数无效！");
		}
		useBaseDao().deleteById(id);
	}

	@Override
	public T getForModify(T entity) throws Exception {
		return getForModify(entity, null);
	}

	@Override
	public T getForModify(T instance, String propertyList) throws Exception {
		T entityPo = get(instance);
		return entityPo;
	}

	@Override
	public void del(PK[] ids) throws Exception {
		for (PK id : ids) {
			this.del(id);
		}
	}

	@Override
	public void del(T entity) throws Exception {
		T entityPo = get(entity);
		if (entityPo == null) {
			throw new Exception("要删除的" + entity.getClass().getSimpleName() + "并不存在！");
		}
		useBaseDao().delete(entityPo);
	}

	@Override
	public T save(T entity) throws Exception {
		return save(entity, getPropertyList());
	}

	@Override
	public T save(T entity, String propertyList) throws Exception {
		
		T entityPo = get(entity);
		if (entityPo==null){
			entityPo=getNew();
			if (getEntityPk(entity)!=null){
				setEntityPk(entityPo,getEntityPk(entity));
			}
			this.copyProperties(entity, entityPo, propertyList,true);
			useBaseDao().save(getWrapper().wrap(baseDao.getEntityClass(), entityPo));
		}else{
			this.copyProperties(entity, entityPo, propertyList,true);
		}
		useBaseDao().saveOrUpdate(getWrapper().wrap(baseDao.getEntityClass(), entityPo));
		
		return entityPo;
	}

	private void setEntityPk(T entity, PK pk) {
		if (entity!=null){
			try {
				PropertyUtils.setProperty(entity, getIdName(), pk);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private PK getEntityPk(T entity) {
		PK id = null;
		
		if (entity!=null){
			try {
				id = (PK)PropertyUtils.getProperty(entity, getIdName());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		return id;
	}

	@Override
	public T update(T entity, String propertyList) throws Exception {
		T po = get(entity);
		this.copyProperties(entity, po, propertyList, true);
		useBaseDao().update(getWrapper().wrap(baseDao.getEntityClass(), po));
		return entity;
	}

	@Override
	public Page<T> manage(Page<T> pageVo) throws Exception {
		// 过滤page中的条件，将相关类转化为实体类
		Page<T2> pagePo = clone(pageVo);			
		
		String exampleProperties = (String)pageVo.getCondition().get(IBaseDao.EXAMPLE_PROPERTIES);
		String exampleProperties2 = null;
		T example = pageVo.getFindByExample();
		if (exampleProperties!=null&&exampleProperties.length()>0){
			String[] propList = exampleProperties.split(",");
			Map<String, String> propertyRelation = getWrapper().getRelation().get(entityClass);
			for(String property:propList){
				if (foreignKeyMap.containsKey(property)){
					Class<?> valusClass = BeanUtilsExt.getPropertyType(entityClass, property);
					Object value = BeanUtilsExt.getPropertyValue(example, property);
					if (!propertyRelation.containsKey(property) && valusClass.equals(entityClass)){
						log.debug("注意，逻辑还不严密！！");
						property += "." + pkName;
					}
					if(propertyRelation.containsKey(property)){
						if (exampleProperties2==null){
							exampleProperties2 = "";
						}else{
							exampleProperties2 += ",";
						}
						exampleProperties2 += propertyRelation.get(property);
					}
				}else{
					if (exampleProperties2==null){
						exampleProperties2 = "";
					}else{
						exampleProperties2 += ",";
					}
					exampleProperties2 += propertyRelation.get(property);
				}

			}
		}
		pagePo.getCondition().put(IBaseDao.EXAMPLE_PROPERTIES, exampleProperties2);

		String propertyList = (String)pageVo.getCondition().get(IBaseDao.PROPERTY_LIST);
		String propertyList2 = null;
		if (propertyList!=null&&propertyList.length()>0){
			String[] propList = propertyList.split(",");
			Map<String, String> propertyRelation = getWrapper().getRelation().get(entityClass);
			for(String property:propList){
				if (foreignKeyMap.containsKey(property)){
					Class<?> valusClass = BeanUtilsExt.getPropertyType(entityClass, property);
				}else{
					if (propertyList2==null){
						propertyList2 = "";
					}else{
						propertyList2 += ",";
					}
					propertyList2 += propertyRelation.get(property);
				}

			}
		}
		pagePo.getCondition().put(IBaseDao.PROPERTY_LIST, propertyList2);
		
		pagePo = useBaseDao().find(pagePo);	
		pageVo.getData().clear();
		for(T2 entry2:pagePo.getData()){
			T entity = getNew();
			BeanUtilsExt.copyProperties(entry2, entity, propertyRelation);
			if (propertyList!=null&&propertyList.length()>0){
				String[] propList = propertyList.split(",");
				Map<String, String> propertyRelation2 = getWrapper().getRelation().get(entityClass);
				for(String property:propList){
					// 如果没有映射
					if (!propertyRelation2.containsKey(property)){
						// 是否有外键
						if (foreignKeyMap.containsKey(property)){
							// 单独查询外键
							log.debug("单独查询外键!");
							Class<?> fkClass = foreignKeyMap.get(property);
						}
						if (oneToMultFkMap.containsKey(property)){
							String f = oneToMultFkMap.get(property);
							String f2 = f;
							if (!propertyRelation2.containsKey(f)){
								f2 = f2 +"."+ pkName;
							}
							f2 = propertyRelation2.get(f2);
							Class<?> fkClass = foreignKeyMap.get(f);
							if (fkClass.equals(entityClass)){
								Object pk2 = PropertyUtils.getProperty(entity, pkName);
								List<T> list = new ArrayList<T>();
								List<T2> list2 = getBaseDao().findByProperty(f2, pk2, "");
								for(T2 e2:list2){
									T e1 = getNew();
									BeanUtilsExt.copyProperties(e2, e1, propertyRelation);
									BeanUtilsExt.setProperty(e1, f, entity);
									list.add(e1);
								}
								BeanUtilsExt.setProperty(entity, property, list);
							}
						}
					}

				}
			}

			pageVo.getData().add(entity);
		}
		clone2(pagePo, pageVo);
		return pageVo;
	}
	
	@Override
	public List<T> getAll(String orderBy, long... firstAndMaxResults) throws Exception{
		List<T> list = new ArrayList<T>();
		
		List<T2> list2 = useBaseDao().findAll(orderBy, firstAndMaxResults);
		for(T2 entity2:list2){
			list.add(getWrapper().wrap(entityClass, list2));
		}
		
		return list;
	}
	
	@Override
	public List<T> findByExample(T entity, String propertyList, String orderBy, long... firstAndMaxResults) throws Exception{
		List<T> list = new ArrayList<T>();
		
		List<T2> list2 = useBaseDao().findByExample(getWrapper().wrap(baseDao.getEntityClass(), entity) , propertyList, orderBy, firstAndMaxResults);
		for(T2 entity2: list2){
			list.add(getWrapper().wrap(entityClass, entity2));
		}
		
		return list;
	}
	
	@Override
	public boolean isUnique(T instance, String propertyList) {
		boolean isUnique = false;
		isUnique = this.getBaseDao().isUnique(getWrapper().wrap(baseDao.getEntityClass(), instance), propertyList);		
		return isUnique;
	}
	
	/**
	 * 获得持久化实体名列表
	 * @return
	 */
	@Override
	public List<Map<String, Object>> getEntityNameList(){
		List<Map<String, Object>> list = null;
		
		try {
			list = useBaseDao().getEntityNameList();
		} catch (Exception e) {
			list = new  ArrayList<Map<String,Object>>();
		}
		
		return list;
	}
	
	@Override
	public String getIdName() {
		String idName = null;
		try {
			if (useBaseDao().isEntity(useBaseDao().getEntityClass())){
				idName = useBaseDao().getPKName();
			}else{
				idName="id";
			}
		} catch (Exception e) {
			idName = null;
		}
		return idName;
	}
	
	/**
     * 获得指定对象在指定查询条件下的位置序号，0算起
     * @param entity
     * @param criteria
     * @param orderBy
     * @return
     */
    public long getIndex(T focus, Page<T> page){
    	long index = 0;
    	if (oldService!=null){
    		
    	}else if(baseDao!=null){
    		Page<T2> page2 = clone(page);
    		index = getBaseDao().getIndex(getWrapper().wrap(baseDao.getEntityClass(), focus), page2);
    	}
    	return index;
    }

	private Page<T2> clone(Page<T> page) {
		Page<T2> page2 = new Page<T2>();
		page2.setStartIndex(page.getStartIndex());
		page2.setPageSize(page.getPageSize());
		page2.setFindByExample(getWrapper().wrap(baseDao.getEntityClass(), page.getFindByExample()));
		page2.setCondition(page.getCondition());
		return page2;
	}

	private Page<T> clone2(Page<T2> page, Page<T> page2) {
		page2.setStartIndex(page.getStartIndex());
		page2.setPageSize(page.getPageSize());
		page2.setFindByExample(getWrapper().wrap(entityClass, page.getFindByExample()));
		page2.setCondition(page.getCondition());
		return page2;
	}

	@Override
	public Map<Class<?>, Map<Serializable, Object>> loadProperties(T entityPo, String propertyList, Map<Class<?>, Map<Serializable, Object>> propertyValueCache)
			throws Exception {
		// TODO Auto-generated method stub
		return  propertyValueCache;
	}

	@Override
	public List<T> findByProperty(String propertyName, Object value, String orderBy, String propertyList, long... firstAndMaxResults) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

}
